package com.minelx.datamicroscope.core.query;

import com.alibaba.fastjson.JSONObject;
import com.minelx.datamicroscope.core.display.DisplayTemplate;
import com.minelx.datamicroscope.core.display.DisplayTemplates;

import java.util.List;
import java.util.Map;

import static java.util.Collections.emptyList;
import static java.util.Collections.emptyMap;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toMap;

class QueryFactory {

    private final ResourcesFactory resourcesFactory;

    private final JSONObject data;

    QueryFactory(ResourcesFactory resourcesFactory, JSONObject data) {
        this.resourcesFactory = resourcesFactory;
        this.data = data;
    }

    Query createQuery() {
        return new Query(
                parseProjection(),
                parseDisplayTemplates(),
                parseQueryPaths(),
                parseHowMapping());
    }

    private Map<String, String> parseHowMapping() {
        if (!data.containsKey("how")) {
            return emptyMap();
        }
        return data.getJSONObject("how").entrySet().stream()
                .collect(toMap(Map.Entry::getKey, entry -> String.valueOf(entry.getValue())));
    }

    private List<DisplayTemplate> parseProjection() {
        if (!data.containsKey("projection")) {
            return emptyList();
        }
        return data.getJSONArray("projection").toJavaList(JSONObject.class).stream()
                .map(DisplayTemplate::new)
                .collect(toList());
    }

    private DisplayTemplates parseDisplayTemplates() {
        if (!data.containsKey("display")) {
            return DisplayTemplates.empty();
        }
        return DisplayTemplates.from(data.getJSONArray("display"));
    }

    private QueryPaths parseQueryPaths() {
        List<JSONObject> collections = data.getJSONArray("collect").toJavaList(JSONObject.class);
        List<QueryPath> queryPaths = collections.subList(1, collections.size()).stream()
                .map(QueryPathFactory::new)
                .map(QueryPathFactory::createQueryPath)
                .collect(toList());
        return createQueryPaths(collections.get(0), queryPaths);
    }

    private QueryPaths createQueryPaths(JSONObject firstCollection,
                                        List<QueryPath> queryPaths) {
        return new QueryPaths(resourcesFactory,
                FirstCollectionQuery.from(firstCollection),
                queryPaths);
    }
}
